package com.rickpan.storage.health;

import com.rickpan.config.MinIOProperties;
import com.rickpan.storage.StorageService;
import io.minio.BucketExistsArgs;
import io.minio.MinioClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 存储健康检查服务
 * 提供存储系统的健康状态监控
 */
@Service
public class StorageHealthService {
    
    private static final Logger logger = LoggerFactory.getLogger(StorageHealthService.class);
    
    @Autowired
    private StorageService storageService;
    
    @Autowired(required = false)
    private MinioClient minioClient;
    
    @Autowired(required = false)
    private MinIOProperties minIOProperties;
    
    // 健康检查缓存（避免频繁检查）
    private volatile HealthStatus cachedHealth;
    private volatile long lastHealthCheckTime = 0;
    private static final long HEALTH_CHECK_CACHE_DURATION = 30000; // 30秒缓存

    public HealthStatus health() {
        long currentTime = System.currentTimeMillis();
        
        // 使用缓存的健康状态（30秒内）
        if (cachedHealth != null && (currentTime - lastHealthCheckTime) < HEALTH_CHECK_CACHE_DURATION) {
            return cachedHealth;
        }
        
        try {
            HealthStatus health = performHealthCheck();
            cachedHealth = health;
            lastHealthCheckTime = currentTime;
            return health;

        } catch (Exception e) {
            logger.error("存储健康检查失败", e);
            HealthStatus health = new HealthStatus("DOWN", Map.of(
                "error", e.getMessage(),
                "timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            ));
            cachedHealth = health;
            lastHealthCheckTime = currentTime;
            return health;
        }
    }
    
    /**
     * 执行健康检查
     */
    private HealthStatus performHealthCheck() {
        String storageType = storageService.getStorageType();
        Map<String, Object> details = new HashMap<>();
        
        details.put("storageType", storageType);
        details.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        
        boolean isHealthy = true;
        StringBuilder issues = new StringBuilder();
        
        try {
            if ("local".equals(storageType)) {
                isHealthy = checkLocalStorageHealth(details, issues);
            } else if ("minio".equals(storageType)) {
                isHealthy = checkMinIOStorageHealth(details, issues);
            } else {
                isHealthy = false;
                issues.append("未知的存储类型: ").append(storageType);
            }
            
            // 通用检查
            checkStorageServiceHealth(details, issues);
            
        } catch (Exception e) {
            isHealthy = false;
            issues.append("健康检查异常: ").append(e.getMessage());
            logger.error("存储健康检查异常", e);
        }
        
        if (isHealthy) {
            return new HealthStatus("UP", details);
        } else {
            details.put("issues", issues.toString());
            return new HealthStatus("DOWN", details);
        }
    }
    
    /**
     * 检查本地存储健康状态
     */
    private boolean checkLocalStorageHealth(Map<String, Object> details, StringBuilder issues) {
        try {
            // 检查存储目录
            String storagePath = "./uploads"; // 从配置获取
            File storageDir = new File(storagePath);
            
            details.put("storagePath", storagePath);
            details.put("storageExists", storageDir.exists());
            details.put("storageWritable", storageDir.canWrite());
            details.put("storageReadable", storageDir.canRead());
            
            if (!storageDir.exists()) {
                issues.append("存储目录不存在: ").append(storagePath).append("; ");
                return false;
            }
            
            if (!storageDir.canWrite()) {
                issues.append("存储目录不可写: ").append(storagePath).append("; ");
                return false;
            }
            
            if (!storageDir.canRead()) {
                issues.append("存储目录不可读: ").append(storagePath).append("; ");
                return false;
            }
            
            // 检查磁盘空间
            long freeSpace = storageDir.getFreeSpace();
            long totalSpace = storageDir.getTotalSpace();
            long usedSpace = totalSpace - freeSpace;
            double usagePercent = (double) usedSpace / totalSpace * 100;
            
            details.put("diskFreeSpace", formatBytes(freeSpace));
            details.put("diskTotalSpace", formatBytes(totalSpace));
            details.put("diskUsagePercent", String.format("%.2f%%", usagePercent));
            
            // 磁盘空间告警（使用率超过90%）
            if (usagePercent > 90) {
                issues.append("磁盘空间不足，使用率: ").append(String.format("%.2f%%", usagePercent)).append("; ");
                return false;
            }
            
            details.put("status", "本地存储健康");
            return true;
            
        } catch (Exception e) {
            issues.append("本地存储检查失败: ").append(e.getMessage()).append("; ");
            return false;
        }
    }
    
    /**
     * 检查 MinIO 存储健康状态
     */
    private boolean checkMinIOStorageHealth(Map<String, Object> details, StringBuilder issues) {
        if (minioClient == null || minIOProperties == null) {
            issues.append("MinIO客户端或配置未初始化; ");
            return false;
        }
        
        try {
            details.put("endpoint", minIOProperties.getEndpoint());
            details.put("bucketName", minIOProperties.getBucketName());
            details.put("region", minIOProperties.getRegion());
            
            // 检查连接和存储桶
            CompletableFuture<Boolean> connectionCheck = CompletableFuture.supplyAsync(() -> {
                try {
                    boolean bucketExists = minioClient.bucketExists(
                        BucketExistsArgs.builder()
                            .bucket(minIOProperties.getBucketName())
                            .build()
                    );
                    return bucketExists;
                } catch (Exception e) {
                    logger.warn("MinIO连接检查失败", e);
                    return false;
                }
            });
            
            // 设置超时时间（10秒）
            Boolean connected = connectionCheck.get(10, TimeUnit.SECONDS);
            
            details.put("connected", connected);
            details.put("bucketExists", connected);
            
            if (!connected) {
                issues.append("MinIO连接失败或存储桶不存在; ");
                return false;
            }
            
            // 检查 MinIO 服务信息（如果可能）
            try {
                // 这里可以添加更多的 MinIO 特定检查
                details.put("status", "MinIO存储健康");
                return true;
                
            } catch (Exception e) {
                logger.warn("MinIO详细检查失败", e);
                details.put("warning", "MinIO详细检查失败: " + e.getMessage());
                return true; // 基本连接正常，详细检查失败不影响整体健康状态
            }
            
        } catch (Exception e) {
            issues.append("MinIO健康检查失败: ").append(e.getMessage()).append("; ");
            details.put("error", e.getMessage());
            return false;
        }
    }
    
    /**
     * 检查存储服务健康状态
     */
    private void checkStorageServiceHealth(Map<String, Object> details, StringBuilder issues) {
        try {
            // 检查存储服务是否可用
            String storageType = storageService.getStorageType();
            details.put("serviceAvailable", true);
            details.put("serviceType", storageType);
            
            // 尝试初始化存储（如果需要）
            storageService.initStorage();
            details.put("initialized", true);
            
        } catch (Exception e) {
            issues.append("存储服务检查失败: ").append(e.getMessage()).append("; ");
            details.put("serviceAvailable", false);
            details.put("initializationError", e.getMessage());
        }
    }
    
    /**
     * 获取详细的健康报告
     */
    public HealthReport getDetailedHealthReport() {
        HealthStatus health = health();

        return new HealthReport(
            health.getStatus(),
            health.getDetails(),
            System.currentTimeMillis()
        );
    }
    
    /**
     * 强制刷新健康检查缓存
     */
    public HealthStatus forceHealthCheck() {
        cachedHealth = null;
        lastHealthCheckTime = 0;
        return health();
    }
    
    /**
     * 格式化字节数
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));
        return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
    }
    
    /**
     * 健康状态
     */
    public static class HealthStatus {
        private final String status;
        private final Map<String, Object> details;

        public HealthStatus(String status, Map<String, Object> details) {
            this.status = status;
            this.details = details;
        }

        public String getStatus() { return status; }
        public Map<String, Object> getDetails() { return details; }
        public boolean isHealthy() { return "UP".equals(status); }
    }

    /**
     * 健康报告
     */
    public static class HealthReport {
        private final String status;
        private final Map<String, Object> details;
        private final long timestamp;

        public HealthReport(String status, Map<String, Object> details, long timestamp) {
            this.status = status;
            this.details = details;
            this.timestamp = timestamp;
        }

        public String getStatus() { return status; }
        public Map<String, Object> getDetails() { return details; }
        public long getTimestamp() { return timestamp; }
        public boolean isHealthy() { return "UP".equals(status); }
    }
}
